<template>
	<view
		class="xt-textarea-main"
		:class="textareaClass"
		:style="{
			borderRadius: border == 'bottom' ? 0 : '8rpx'
		}"
	>
		<textarea
			:style="{
				width: '100%',
				height: handlePixel(height),
				fontSize: handlePixel(fontSize)
			}"
			:value="inputValue"
			:placeholder="placeholder"
			:placeholder-class="placeholderClass"
			:placeholder-style="pStyle"
			:maxlength="maxlength"
			:disabled="disabled"
			:focus="focus"
			:auto-focus="autoFocus"
			:auto-height="autoHeight"
			:fixed="fixed"
			:cursor-spacing="cursorSpacing"
			:cursor="cursor"
			:cursor-color="cursorColor"
			:confirm-type="confirmType"
			:confirm-hold="confirmHold"
			:show-confirm-bar="showConfirmBar"
			:selection-start="selectionStart"
			:selection-end="selectionEnd"
			:adjust-position="adjustPosition"
			:disable-default-padding="disableDefaultPadding"
			:hold-keyboard="holdKeyboard"
			:auto-blur="autoBlur"
			:ignoreCompositionEvent="ignoreCompositionEvent"
			:inputmode="inputmode"
			@focus="xtFocus"
			@blur="xtBlur"
			@linechange="xtLineChange"
			@input="xtInput"
			@confirm="xtConfirm"
			@keyboardheightchange="xtKeyboardheightchange"
		></textarea>
		<view
			class="xt-textarea-count"
			v-if="count"
			:style="{
				'background-color': 'transparent'
			}"
		>
			{{ inputValue.length }}{{ maxlength == -1 ? '' : '/' + maxlength }}
		</view>
	</view>
</template>
<script>
// #ifdef VUE3
import { nextTick } from 'vue';
// #endif
import props from './props.js';
/**
 * Textarea 文本域
 * @description 本组件提供一个文本域的功能，让开发者开发起来更加得心应手。减少重复的模板代码
 * @tutorial https://ext.dcloud.net.cn/plugin?name=xt-textarea
 *
 * @property {String | Number}      value             		绑定的值
 * @property {String} 				border  				输入框的边框样式。默认为 surround。可选 bottom,none
 * @property {String | Number} 		fontSize 				输入框字体大小（默认 '32rpx'）
 * @property {String | Number}		placeholder				输入框为空时占位符
 * @property {String}			    placeholderClass		指定placeholder的样式类，注意页面或组件的style中写了scoped时，需要在类名前写/deep/ （ 默认 'textarea-placeholder' ）
 * @property {String | Object}	    placeholderStyle		指定placeholder的样式，字符串/对象形式
 * @property {String | Number}		height					输入框高度（默认 140rpx ）
 * @property {String}				confirmType				设置键盘右下角按钮的文字，仅微信小程序，App-vue和H5有效（默认 'done' ）
 * @property {Boolean}				disabled				是否禁用（默认 false ）
 * @property {Boolean}				count					是否显示统计字数（默认 false ）
 * @property {Boolean}				focus					是否自动获取焦点，nvue不支持，H5取决于浏览器的实现（默认 false ）
 * @property {Boolean}				autoHeight				是否自动增加高度（默认 false ）
 * @property {Boolean}				fixed					如果textarea是在一个position:fixed的区域，需要显示指定属性fixed为true（默认 false ）
 * @property {Number}				cursorSpacing			指定光标与键盘的距离（默认 0 ）
 * @property {String | Number}		cursor					指定focus时的光标位置
 * @property {Function}			    formatter			    内容式化函数
 * @property {Boolean}				showConfirmBar			是否显示键盘上方带有”完成“按钮那一栏，（默认 true ）
 * @property {Number}				selectionStart			光标起始位置，自动聚焦时有效，需与selection-end搭配使用，（默认 -1 ）
 * @property {Number | Number}		selectionEnd			光标结束位置，自动聚焦时有效，需与selection-start搭配使用（默认 -1 ）
 * @property {Boolean}				adjustPosition			键盘弹起时，是否自动上推页面（默认 true ）
 * @property {Boolean | Number}		disableDefaultPadding	是否去掉 iOS 下的默认内边距，只微信小程序有效（默认 false ）
 * @property {Boolean}				holdKeyboard			focus时，点击页面的时候不收起键盘，只微信小程序有效（默认 false ）
 * @property {String | Number}		maxlength				最大输入长度，设置为 -1 的时候不限制最大长度（默认 140 ）
 * @property {Boolean}				ignoreCompositionEvent	是否忽略组件内对文本合成系统事件的处理
 *
 * @event {Function(e)} 			focus					输入框聚焦时触发
 * @event {Function(e)} 			blur					输入框失去焦点时触发
 * @event {Function(e)} 			linechange				输入框行数变化时调用
 * @event {Function(e)} 			input					键盘输入时，触发 input 事件
 * @event {Function(e)} 			confirm					点击完成时， 触发 confirm 事件
 * @event {Function(e)} 			keyboardheightchange	键盘高度发生变化的时候触发此事件
 * @example <xt-textarea></xt-textarea>
 */
export default {
	name: 'xt-textarea',
	mixins: [props],
	data() {
		return {
			inputValue: '',
			pStyle: '',
			// 焦点状态
			focused: false,
			// 是否格式化
			isFormat: false,
			// 内部变化
			internal: false,
			// 是否初始化
			isInit: false,
			// 是否第一次变化
			firstChange: true
		};
	},
	computed: {
		textareaClass() {
			let cls = [];
			cls.push('xt-textarea-border-' + this.border);
			if (this.disabled) {
				cls.push('xt-textarea-disabled');
			}
			return cls;
		}
	},
	watch: {
		value: {
			immediate: true,
			handler(newVal, oldVal) {
				if (this.internal || this.inputValue === newVal) {
					this.internal = false;
					return;
				}
				this.inputValue = newVal;
				if (this.firstChange) {
					this.formValidate(this, 'change');
				}
				// 在WEB中，外部value变化后，修改input中的值，不会触发@input事件，此时手动调用值变化方法
				if (this.firstChange === false && this.internal === false) {
					this.inputChange(this.inputValue, false);
				} else {
					// 调用xt-form的校验
					if (!this.firstChange) this.formValidate(this, 'change');
				}
				this.firstChange = false;
				this.internal = false;
			}
		},
		// #ifdef VUE3
		modelValue: {
			immediate: true,
			handler(newVal, oldVal) {
				if (this.internal || this.inputValue === newVal) {
					this.internal = false;
					return;
				}
				if (this.value != '' && this.value != void 0 && this.value != null) {
					this.inputValue = this.value;
					return;
				}
				this.inputValue = newVal;
				if (this.firstChange) {
					this.formValidate(this, 'change');
				}
				// 在WEB中，外部value变化后，修改input中的值，不会触发@input事件，此时手动调用值变化方法
				if (this.firstChange === false && this.internal === false) {
					this.inputChange(this.inputValue, false);
				} else {
					// 调用xt-form的校验
					if (!this.firstChange) this.formValidate(this, 'change');
				}
				this.firstChange = false;
				this.internal = false;
			}
		}
		// #endif
	},
	methods: {
		getParent(name = undefined) {
			let parent = this.$parent;
			while (parent) {
				// 父组件
				if (parent.$options && parent.$options.name !== name) {
					// 如果组件的name不相等，继续上一级寻找
					parent = parent.$parent;
				} else {
					return parent;
				}
			}
			return false;
		},
		formValidate(instance, event) {
			const formItem = this.getParent.call(instance, 'xt-form-item');
			const form = this.getParent.call(instance, 'xt-form');
			if (formItem && form) {
				form.validateField(formItem.prop, () => {}, event);
			}
		},
		xtBlur(e) {
			this.$emit('blur', e);
			this.formValidate(this, 'blur');
		},
		xtFocus(e) {
			this.$emit('focus', e);
		},
		xtInput(e) {
			this.inputValue = e.detail.value;
			const value = this.isFormat ? this.formatter(e.detail.value) : e.detail.value;
			this.handleVue(() => {
				this.inputChange(value);
			});
		},
		xtKeyboardheightchange(e) {
			this.$emit('keyboardheightchange', e);
		},
		xtConfirm(e) {
			this.$emit('confirm', e);
		},
		xtLineChange(e) {
			this.$emit('linechange', e);
		},
		handleVue(func) {
			// #ifdef VUE2
			this.$nextTick(() => {
				func();
			});
			// #endif
			// #ifdef VUE3
			nextTick(() => {
				func();
			});
			// #endif
		},
		handleStyle(obj) {
			return Object.entries(obj)
				.map(([key, value]) => `${key}:${value}`)
				.join(';');
		},
		handlePixel(value = 'auto', unit = 'px', count, type) {
			const unitRegex = /^(\d+(\.\d+)?)([a-zA-Z%]+)?$/;
			let valueNum = value;
			let valueUnit = unit;
			let countNum = count;
			let countUnit = unit;
			let result = value;

			// 处理 value 参数
			if (typeof value === 'string' && unitRegex.test(value)) {
				const valueMatch = value.match(unitRegex);
				valueNum = Number(valueMatch[1]); // 数字部分
				result = valueNum; // 初始结果是数字部分
				valueUnit = valueMatch[3] || unit; // 单位部分（如果有）
			}

			// 处理 count 参数
			if (typeof count === 'string' && unitRegex.test(count)) {
				const countMatch = count.match(unitRegex);
				countNum = Number(countMatch[1]); // 数字部分
				countUnit = countMatch[3] || unit; // 单位部分
			}

			// 进行相应的运算
			if (valueNum > 0 && countNum > 0) {
				switch (type) {
					case '+':
						result = valueNum + countNum;
						break;
					case '-':
						result = valueNum - countNum;
						break;
					case '*':
						result = valueNum * countNum;
						break;
					case '/':
						result = valueNum / countNum;
						break;
				}
			}

			// 返回结果时，附上单位部分
			return result + (valueUnit || '');
		},
		inputChange(e, xt = true) {
			const value = e || this.inputValue;
			this.inputValue = value;
			this.handleVue(() => {
				// #ifdef VUE3
				this.$emit('update:modelValue', value);
				// #endif
				this.internal = xt;
				this.$emit('input', value);
			});
			this.formValidate(this, 'change');
		}
	},
	mounted() {
		this.pStyle = typeof this.placeholderStyle === 'string' ? this.placeholderStyle : this.handleStyle(this.placeholderStyle);
		if (typeof this.formatter === 'function') {
			this.isFormat = true;
		} else {
			this.isFormat = false;
		}
	}
};
</script>
<style scoped>
@import './style.css';
</style>
